package ipc;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HMSExperimenter {
	
	public int nRuns;
	public int runid;
	

	public List<iterationData> iData = null; // :-)
	public runInfo rinfo;
	public preSolve presolve = new preSolve();
	public postSolve postsolve = new postSolve();
	public static int staticRunID = 20000;

	public void addPreSolve(preSolve ps){
		presolve.addpreSolve(ps);
	}
	
	public void addIterationData(List<iterationData> id){
		
		if( iData == null ){
			iData = new ArrayList<iterationData>(id);
		}else if( id.size() == iData.size() ){
			for( int i = 0 ; i < iData.size(); ++i ){
				iData.get(i).addIterationData(id.get(i));
			}
		}
		
	}
	
	public void addPostSolve(postSolve ps){
		postsolve.addPostSolve(ps);
	}
	
	public void finishUp(){
		presolve.finishUp(nRuns);
		postsolve.finishUp(nRuns);
		for( iterationData id : iData ){
			id.finishUp(nRuns);
		}
	}
	
	public HMSExperimenter( String dbname, int nRuns, String domain, String instance, String type) throws SQLException, ClassNotFoundException{
		runid = staticRunID++;
		
//		DBLogger dbl = new DBLogger(dbname);
//		dbl.connect();
		
		this.nRuns = nRuns;

		boolean dontenterintodb = false;
		
		int r = 0;
		while ( r < nRuns ){

			preSolve pre = null ;
			postSolve post = null ;
			List<iterationData> iter = null;
			Class theclass = null;
			
			if( type.equals("ADD") ){
				theclass = ValueIteration.class;
			}else if( type.equals("ADD-CONC") ){
				theclass = ValueIterationConcurrent.class;
			}else if( type.equals("AADD") ){
				theclass = ValueIterationAADD.class;
			}else if( type.equals("AADD-CONC") ){
				theclass = ValueIterationConcurrentAADD.class;
			}else{
				dontenterintodb = false;
				break;
			}
			
			Worker wrker = null;
				
			try {
				wrker = new Worker(theclass, domain, instance, 0.1, ValueIteration.ORDER_GUESS, -1, "./");
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.exit(1);
			}
			
				
			try {
				Thread t = new Thread(wrker);
				t.run();
//					t.join();
				t.join(60*60*1000L);
				

				if( type.equals("ADD") ){
					ValueIteration vi = (ValueIteration)wrker.actualObject;
					pre = vi.presolve;
					post = vi.postsolve;
					iter = vi.iData;
					if( r == 0 ){
						rinfo = vi.rInfo;
					}
				}else if( type.equals("ADD-CONC") ){
					ValueIterationConcurrent vi = (ValueIterationConcurrent)wrker.actualObject;
					pre = vi.presolve;
					post = vi.postsolve;
					iter = vi.iData;
					if( r == 0 ){
						rinfo = vi.rInfo;
					}
				}else if( type.equals("AADD") ){
					ValueIterationAADD vi = (ValueIterationAADD)wrker.actualObject;
					pre = vi.presolve;
					post = vi.postsolve;
					iter = vi.iData;
					if( r == 0 ){
						rinfo = vi.rInfo;
					}
				}else if( type.equals("AADD-CONC") ){
					ValueIterationConcurrentAADD vi = (ValueIterationConcurrentAADD)wrker.actualObject;
					pre = vi.presolve;
					post = vi.postsolve;
					iter = vi.iData;
					if( r == 0 ){
						rinfo = vi.rInfo;
					}
				}else{
					dontenterintodb = false;
					break;
				}
				
				addPreSolve(pre);
				addIterationData(iter);
				addPostSolve(post);
				++r;
				
			} catch (Exception e) {
				e.printStackTrace();
				//did not complete in 2 hours
				//dont make an entry
				dontenterintodb = true;
				break;
			}
			
			
			
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
				
		if( !dontenterintodb){
			finishUp();

//			String[] sql = makeQueries();
//			
//			for( String s : sql ){
//				dbl.addToBatch(s);
//			}
//			dbl.execute();

			System.out.println(rinfo);
			System.out.println(presolve);
			System.out.println(postsolve);
			System.out.println(iData);

		}
		
//		dbl.close();
		//doVi on a worker thread nrun times
		//add data from vi obj to hms
		//finishup
		//construct query
		//write out
	}

	private String[] makeQueries() {
		String[] ret = new String[iData.size()+3];
		
		int i = 0;
		for( i = 0 ; i < iData.size(); ++i ){
			ret[i] = iData.get(i).toInsert(runid);
		}
	
		ret[i++] = rinfo.toInsert(runid);
		ret[i++] = presolve.toInsert(runid);
		ret[i++] = postsolve.toInsert(runid);
		
		return ret;
	}
	
	public static void main(String[] args) throws SQLException, ClassNotFoundException {
		
		
		Map<String, List<String> > experiments = new HashMap<String, List<String>>();
		
//		List<String> uniring = new ArrayList<String>();
//		for( int i = 0; i <= 3 ; ++i ){
//			uniring.add("./rddl/sysadmin_ringofring_3_4_combined_"+i+".rddl");	
//		}
//		experiments.put("./rddl/sysadmin_mdp_same.rddl", uniring);
		List<String> elevs = new ArrayList<String>();
		for( int i = 3 ; i <= 10; ++i ){
			for( int j = 1; j <= 10; ++j ){
				elevs.add("./rddl/my_elevators_inst_mdp__"+i+"_"+j+".rddl");
			}
		}
		experiments.put("./rddl/my_elevators_mdp.rddl", elevs);
		
//		List<String> starandbiring = new ArrayList<String>();
//		for( int deg = 2 ; deg <= 2; ++deg ){
//			for( int i = 13; i <= 13 ; ++i ){
//				starandbiring.add("/scratch/final_comp/rddl/sysadmin_star_"+i+"_"+deg+".rddl");
//				starandbiring.add("/scratch/final_comp/rddl/sysadmin_biring_"+i+"_"+deg+".rddl");	
//			}	
//		}
		
//		experiments.put("/scratch/final_comp/rddl/sysadmin_mdp.rddl", starandbiring);
		
//		List<String> elev = new ArrayList<String>();
//		for( int i = 1 ; i <= 10; ++i ){
//			elev.add("./rddl/elevators_inst_mdp__"+i+".rddl");
//		}
//		experiments.put("./rddl/elevators_mdp.rddl", elev);
//
		String[] types = {"ADD", "ADD-CONC", "AADD", "AADD-CONC"};
		System.out.println(experiments); 
		
		for( Map.Entry<String, List<String>> entry : experiments.entrySet() ){
			
			String domain = entry.getKey();
			List<String> instances = entry.getValue();
			for( String instance : instances ){
				System.out.println("Solving " + domain +  " " + instance );
				for( String type : types ){
					System.out.println(type);
					new HMSExperimenter("concvi", 1, domain, instance, type);
				}
			}
		}
		
//		String[] domains = {
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp_same.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp_same.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp_same.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp_same.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////				"/scratch/final_comp/rddl/crossing_traffic_multi.rddl"
//				"/scratch/final_comp/rddl/sysadmin_mdp_same.rddl"
////							"/scratch/final_comp/rddl/skill_teaching_mdp.rddl",
////							
////							
////							"/scratch/final_comp/rddl/crossing_traffic_mdp.rddl",
////							"/scratch/final_comp/rddl/navigation_mdp.rddl",
////							"/scratch/final_comp/rddl/sysadmin_mdp.rddl",
////							"/scratch/final_comp/rddl/elevators_mdp.rddl",
////							"/scratch/final_comp/rddl/game_of_life_mdp.rddl",
////							
////							"/scratch/final_comp/rddl/recon_mdp.rddl",
////							"/scratch/final_comp/rddl/traffic_mdp.rddl"
//							}; 
//		
//		String[] instances = {
////				"/scratch/final_comp/rddl/sysadmin_uniring_3_1.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_3_2.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_3_combined.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_4_1.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_4_2.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_4_combined.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_5_1.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_5_2.rddl",
//				"/scratch/final_comp/rddl/sysadmin_uniring_5_combined.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_6_1.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_6_2.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_6_combined.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_7_1.rddl",
////				"/scratch/final_comp/rddl/sysadmin_uniring_7_2.rddl",
////				"/scratch/final_comp/rddl/crossing_traffic_multi_inst_mdp__1.rddl"
////				"/scratch/final_comp/rddl/sysadmin_uniring_7_combined.rddl"
////							"/scratch/final_comp/rddl/skill_teaching_inst_mdp__1.rddl",
////							
////							
////							"/scratch/final_comp/rddl/crossing_traffic_inst_mdp__1.rddl",
////							"/scratch/final_comp/rddl/navigation_inst_mdp__1.rddl",
////							"/scratch/final_comp/rddl/sysadmin_inst_mdp__1.rddl",
////							"/scratch/final_comp/rddl/elevators_inst_mdp__1.rddl",
////							"/scratch/final_comp/rddl/game_of_life_inst_mdp__1.rddl",
////							
////							"/scratch/final_comp/rddl/recon_inst_mdp__1.rddl",
////							"/scratch/final_comp/rddl/traffic_inst_mdp__1.rddl"
//							};
//		
//		/*
//		 * todo
//		 *	 traffic all
//		 *	 game of life AADD both
//		 *	
//		 */
//		
//		String[] types = {"ADD", "ADD-CONC", "AADD", "AADD-CONC"};
//		
//		for( int i = 0 ; i < domains.length; ++i ){
//			String domain = domains[i];
//			String instance = instances[i];
//			
//			System.out.println("Solving " + domain +  " " + instance );
//			
//			for( String type : types ){
//				
//				System.out.println(type);
//				new HMSExperimenter("concvi", 1, domain, instance, -1, type);
//				
//			}
//			
//			
//			
//		}
		
		
	}
}
